package com.my.core.util.geo;


import java.util.ArrayList;
import java.util.List;

/**
 * Geometry 工具类
 */
public class GeometryUtils {

    // 地球半径（千米）
    private static final double EARTH_RADIUS = 6371;

    /**
     * String字符串 转 WKT字符串
     *
     * @param geoType   circle:圆形；rectangle:矩形；polygon:多边形
     * @param positions 106.44867038023533,31.482288428342724;106.39118021023812,31.426323476387076;106.50243705130926,31.384663017045437;106.51832173179496,31.454143024188557;106.44867038023533,31.482288428342724
     * @return POINT / POLYGON(( 106.44867038023533 31.482288428342724, 106.39118021023812 31.426323476387076, 106.50243705130926 31.384663017045437, 106.51832173179496 31.454143024188557, 106.44867038023533 31.482288428342724))
     */
    public static String joinPoints(String geoType, String positions) throws IllegalAccessException {
        String geometry = "";
        if (geoType.equals(CommonEnum.GEO_TYPE_CIRCLE.getText())) {
            String[] points = positions.split(",");
            if (points.length < 2) {
                throw new IllegalAccessException( "圆形经纬度坐标异常！");
            }
            geometry = "POINT(" + points[0] + " " + points[1] + ")";
        } else if (geoType.equals(CommonEnum.GEO_TYPE_RECTANGLE.getText())) {
            String[] split = positions.split(";");
            if (split.length < 2) {
                throw new IllegalAccessException( "矩形经纬度坐标异常！");
            }
            //矩形第一个点
            String[] pointOne = split[0].split(",");
            String pointX1 = pointOne[0];
            String pointy1 = pointOne[1];
            //矩形第二个点
            String[] pointTwo = split[1].split(",");
            String pointX2 = pointTwo[0];
            String pointy2 = pointTwo[1];
            geometry = "POLYGON((" + pointX1 + " " + pointy1 + "," +
                    pointX2 + " " + pointy1 + "," +
                    pointX2 + " " + pointy2 + "," +
                    pointX1 + " " + pointy2 + "," +
                    pointX1 + " " + pointy1 +
                    "))";
        } else if (geoType.equals(CommonEnum.GEO_TYPE_POLYGON.getText())) {
            String[] points = positions.split(";");
            List<String> pointList = new ArrayList<>();
            for (String point : points) {
                String[] split = point.split(",");
                pointList.add(split[0] + " " + split[1]);
            }
            geometry = "POLYGON((" + String.join(",", pointList) + "))";
        }
        return geometry;
    }

    /**
     * 计算中心点位
     *
     * @param positions 106.44867038023533,31.482288428342724;106.39118021023812,31.426323476387076;
     *                  106.50243705130926,31.384663017045437;106.51832173179496,31.454143024188557;
     *                  106.44867038023533,31.482288428342724
     * @return double[]
     */
    public static String calculationCenterPoint(String positions) {
        double[] pointArr = calculateCentroid(convert(positions));
        return "POINT(" + pointArr[0] + " " + pointArr[1] + ")";
    }

    /**
     * 计算中心点位
     *
     * @param pointArrayStr [[[106.62259497927492,31.46373695474591],[106.62266839321707,31.463672269317517],
     *                      [106.62273391870433,31.463607209440653],[106.62275234126162,31.46358853966934],
     *                      [106.62207695638638,31.463851162671105],[106.62217967261265,31.46384926655071],
     *                      [106.62228016298864,31.463839072484685],[106.62239719891326,31.463822126835357],
     *                      [106.62248153012276,31.463800837758036],[106.62253388155204,31.46377698034832],
     *                      [106.62259497927492,31.46373695474591]]]
     * @return POINT WKT
     */
//    public static String pointArrayStrToCenterPoint(String pointArrayStr) {
//        double[][][] pointArray = JsonUtil.fromJson(pointArrayStr, double[][][].class);
//        double[] pointArr = calculateCentroid(pointArray[0]);
//        return "POINT(" + pointArr[0] + " " + pointArr[1] + ")";
//    }
//
//    public static <T> T fromJson(String json, Class<T> clazz) {
//        try {
//            return objectMapper.readValue(json, clazz);
//        } catch (Exception e) {
//            throw new RuntimeException("Error converting JSON to object", e);
//        }
//    }

    /**
     * 计算中心点位
     *
     * @param points 二维数组
     * @return double[]
     */
    public static double[] calculateCentroid(double[][] points) {
        if (points.length == 1) {
            return new double[]{points[0][0], points[0][1]};
        }
        double sumX = 0.0;
        double sumY = 0.0;
        double area = 0.0;

        int n = points.length;

        for (int i = 0; i < n - 1; i++) {
            double x1 = points[i][0];
            double y1 = points[i][1];
            double x2 = points[i + 1][0];
            double y2 = points[i + 1][1];

            double factor = x1 * y2 - x2 * y1;
            area += factor;
            sumX += (x1 + x2) * factor;
            sumY += (y1 + y2) * factor;
        }

        // 处理闭合点与第一个点的关系
        double x1 = points[n - 1][0];
        double y1 = points[n - 1][1];
        double x2 = points[0][0];
        double y2 = points[0][1];
        double factor = x1 * y2 - x2 * y1;
        area += factor;
        sumX += (x1 + x2) * factor;
        sumY += (y1 + y2) * factor;

        // 计算最终结果
        area /= 2.0;
        double cX = sumX / (6.0 * area);
        double cY = sumY / (6.0 * area);

        return new double[]{cX, cY};
    }

    /**
     * 字符串 转二维数组
     *
     * @param positions POINT/POLYGON((106.44867038023533 31.482288428342724, 106.39118021023812 31.426323476387076, 106.50243705130926 31.384663017045437, 106.51832173179496 31.454143024188557, 106.44867038023533 31.482288428342724))
     * @return double[][]
     */
    public static double[][] convert(String positions) {
        positions = positions.replaceAll("POINT", "").replaceAll("POLYGON", "")
                .replaceAll("\\(\\(", "").replaceAll("\\)\\)", "");

        String[] pointOneArr = positions.split(",");

        double[][] result = new double[pointOneArr.length][];

        for (int i = 0; i < pointOneArr.length; i++) {
            String[] pointTwoArr = pointOneArr[i].split(" ");
            result[i] = new double[pointTwoArr.length];
            for (int j = 0; j < pointTwoArr.length; j++) {
                result[i][j] = Double.parseDouble(pointTwoArr[j]);
            }
        }

        return result;
    }

    /**
     * 使用 Haversine 公式计算两点间距离
     *
     * @param lat1 起点纬度
     * @param lon1 起点经度
     * @param lat2 终点纬度
     * @param lon2 终点经度
     * @return 距离（米）
     */
    public static double haversine(double lat1, double lon1, double lat2, double lon2) {
        // 将角度转换为弧度
        double lat1Rad = Math.toRadians(lat1);
        double lon1Rad = Math.toRadians(lon1);
        double lat2Rad = Math.toRadians(lat2);
        double lon2Rad = Math.toRadians(lon2);

        // 计算纬度差和经度差
        double dLat = lat2Rad - lat1Rad;
        double dLon = lon2Rad - lon1Rad;

        // Haversine 公式
        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
                Math.cos(lat1Rad) * Math.cos(lat2Rad) *
                        Math.sin(dLon / 2) * Math.sin(dLon / 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

        // 计算距离
        return Math.round(EARTH_RADIUS * c * 1000);
    }
}

